/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 *
 *
 * \file
 * \brief This is an example for using the FleetCtrlClient from Machine control Interface.
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 */
#include "FleetCtrlClient.hpp"
#include "MachineCtrlClient.hpp"
#include "gimi.h"
//*****************************************************************************
#define GIMI_CLIENT_API 20000
#include "gimi.h"
//*****************************************************************************
using namespace MaCI::MachineCtrl;
//*****************************************************************************
static int verbose = 1;
//*****************************************************************************
static volatile bool run = true;
static ownThreadHandle signalHandlerThread;
//*****************************************************************************

void showUsage()
{
  fprintf(stderr,"\n");
  fprintf(stderr,"Usage:\tMachineControlClientExample [OPTIONS]\n");
  fprintf(stderr,"  [-u addr]\t\t\tUse 'addr' as GIMnet AccessPoints address\n");
  fprintf(stderr,"  [-p port]\t\t\tUse 'port' as GIMnet AccessPoints port\n");
  fprintf(stderr,"  [-n name]\t\t\tUse 'name' as this nodes GIMnet name\n");
  fprintf(stderr,"  [-F name]\t\t\tMaCI fleet name\n\n");
  fprintf(stderr,"  [-v]\t\t\t\tIncrease verbosity by 1\n");
  fprintf(stderr,"  [-q]\t\t\t\tQuiet mode\n");
  fprintf(stderr, "\n\n");
}
//*****************************************************************************

static int SignalHandlerThread(void *)
{
  dPrint(8, "Signal handler thread (%ld) starting...", pthread_self());

  while (run) {
    // Now, wait for requested signals to arrive
    int sig;
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    sigaddset(&mask, SIGPIPE);
    sigaddset(&mask, SIGHUP);
    sigwait(&mask, &sig);

    // Got signal, sigwait returned!
    dPrint(1,"Got Signal '%d' (%s)", sig, strsignal(sig));

    // What to do?
    switch(sig) {
    case SIGINT:
    case SIGTERM:
    case SIGPIPE:
    case SIGHUP:
      dPrint(1,"Terminating...");
      run = false;
      //   g.stop();
      dPrint(1,"Waiting 3 seconds for cleanup...");
      ownSleep_ms(2000);
      dPrint(1,"Exit.");
      ownSleep_ms(1000);
      exit(1); // Force :)
      break;
      
    default:
      dPrint(1,"Unhandled signal! Ignore!");
      break;
    }
  }
  return 0;
}
//*****************************************************************************

static void InitSignalHandler(void)
{
  // Now; Set to BLOCK ALL SIGNALS
  sigset_t mask;
  sigemptyset(&mask);
  sigaddset(&mask, SIGINT);
  sigaddset(&mask, SIGTERM);
  sigaddset(&mask, SIGPIPE);
  sigaddset(&mask, SIGHUP);
  pthread_sigmask(SIG_BLOCK, &mask, NULL);
  
  // Start signal handler thread
  signalHandlerThread = ownThread_Create((void*)SignalHandlerThread, NULL);
}
//*****************************************************************************

//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
int main(int argc, char *argv[]) 
{
  // Init Debug lib
  debugInit();
  debugSetGlobalDebugLvl(2);
  // GIMnet parameters
  std::string gimnetAP = "localhost";
  int gimnetAPPort = 40002;
  std::string gimnetName = "";
  std::string gimnetSourceName = "";
  std::string datasourceMaCISL;
  std::string fleetName ="FSRSim";
  
  
  // InitSignalHandler
  InitSignalHandler();
  // Greet
  fprintf(stderr,
	  "\nPositionClientExample - MaCI Position Interface Example - v1.0 Beta\n");
  
  
  
  // Parse parameters
  bool parse = true;
  while(parse) {
    int c;
    c = getopt(argc, argv, "G:n:u:F:p:hqv");
    switch(c) {

      /////////////////////////////////
      ////// Application specific /////
      /////////////////////////////////
      
      /////////////////////////////////
      ///// GIMnet parameters /////////
      /////////////////////////////////
      
    case 'F':
      fleetName = optarg;
      dPrint(3,"Using FleetName '%s'", optarg);
      break;
      
    case 'n':
      gimnetName = optarg;
      dPrint(3,"Using GIMnet Name '%s'", optarg);
      break;
      
    case 'u':
      gimnetAP = optarg;
      dPrint(3,"Using GIMnetAP address '%s'", optarg);
      break;

    case 'p':
      gimnetAPPort = atoi(optarg);
      dPrint(3,"Using GIMnetAP port '%d'", gimnetAPPort);
      break;

      //////////////////////////////////
      //// GENERIC:                 ////
      //////////////////////////////////
    case 'v':
      // Increase only if not previously set to 0 (by 'quiet')
      if (verbose > 0)
	debugSetGlobalDebugLvl(++verbose);
      break;
      
    case 'q':
      verbose = 0;
      debugSetGlobalDebugLvl(0);
      break;
      
    case 'h':
    case '?':
      showUsage();
      exit(1);
      break;
      
    case -1:
      parse = false;
      break;
    }
  }
  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * * * * N O R M A L * * M O D E * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");
  ownSleep_ms(2500);
  dPrint(1,"Constructing FleetCtrlClient...");
  //Construct fleet by giving gimnet AP address, port and the fleet name
  CFleetCtrlClient fleet(gimnetAP,
                         gimnetAPPort,
                         fleetName);

  // Connect the fleet
  fleet.ConnectFleet();

  //Get number of machines in the fleet
  unsigned int fsize = fleet.GetFleetSize();
  dPrint(1,"Fleet size is %d",fsize);

  //Get a list of  names of the machines and print them
  TMachineNameList machineNameList = fleet.GetMachineNames();
  dPrint(1,"Printing machine names");
  for(unsigned int i = 0; i < machineNameList.size();i++){
    dPrintLCGreen(1,"Machine n.%d name = '%s'. Printing its services:",i,machineNameList[i].c_str());
    // Get a pointer to machine(CMachineCtrlClient) by asking it with machine name
    MaCI::MachineCtrl::CMachineCtrlClient *machineclient = fleet.GetMachine(machineNameList[i].c_str());

    if(machineclient != NULL){
      TMaCIMachineComponents components;
      //Get all the machine services and print them
      machineclient->GetMachineComponents(components);
      dPrint(1,"Machine '%s' consists of %d clients:",machineNameList[i].c_str(),components.size());
      for(EACH_IN_j(components)){
        dPrint(1,"interface type %d, instance name: %s",j->first,j->second.c_str());


      }
      
      
    }
    
    
  }
    
  //Then get a map of all machines
  dPrintLCGreen(1,"*****Try by getting the whole map of machines and accessing the machines*****");
  TMachines mapOfMachines = fleet.GetAllMachines();

  int index = 0;
  for(EACH_IN_i(mapOfMachines)){
    dPrint(1,"Name of machine n. %d is %s",index, i->first.c_str());
    MaCI::MachineCtrl::CMachineCtrlClient *machineclient = i->second;

    if(machineclient != NULL){
      TMaCIMachineComponents components;
      //Get all the machine services and print them
      machineclient->GetMachineComponents(components);
      dPrint(1,"Machine '%s' consists of %d clients:",i->first.c_str(),components.size());
      for(EACH_IN_j(components)){
        dPrint(1,"interface type %d, instance name: %s",j->first,j->second.c_str());


      }
    }else{
      dPrint(1,"WTF a NULL Machine!!?!11!?");
    }



    index++;
  }

  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * C O N T I N U O S * * M O D E * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");
  dPrintLCGreen(1," * * * * * * * * * * * * * * * * * * * * * * * * *");
  dPrintLCGreen(1,"* * * * * * * * * * * * * * * * * * * * * * * * * ");



  dPrintLCGreen(1,"Then testing in continuos mode");
  ownSleep_ms(2500);
  CFleetCtrlClient fleet2(gimnetAP,
                          gimnetAPPort,
                          fleetName,
                          true);
  fleet2.ConnectFleet();

  while(run){
    dPrint(1,"Fleet size is %d",fsize);
    TMachineNameList machineNameList2 = fleet2.GetMachineNames();
    dPrint(1,"Printing machine names");
    for(unsigned int i = 0; i < machineNameList2.size();i++){
      dPrintLCGreen(1,"Machine n.%d name = '%s'.",i,machineNameList2[i].c_str());
    }
    ownSleep_ms(10000);

  }
}


